﻿#region Includes
using System;
using System.Collections.Generic;
using OpenTK;
#endregion

namespace GingerGL.Math
{
    [Serializable]
    public struct BoundingCylinderXY : IEquatable<BoundingCylinderXY>
    {
        #region Variables
        public Vector2 Center;
        public float MaxZ;
        public float MinZ;
        public float Radius;

        static public BoundingCylinderXY Empty = new BoundingCylinderXY(new Vector3(0, 0, 0), 0, 0);
        #endregion

        #region Constructors
        public BoundingCylinderXY(Vector3 cp, float height, float radius)
        {
            Center.X = cp.X;
            Center.Y = cp.Y;

            Radius = radius;

            MinZ = cp.Z;
            MaxZ = cp.Z + height;
        }
        #endregion

        #region Methods

        public ContainmentType Contains(BoundingBox box)
        {
            // above or below
            if (box.Min.Z > MaxZ || box.Max.Z < MinZ)
                return ContainmentType.Disjoint;

            // for containment it MUST fit in Z
            if (MaxZ <= box.Max.Z && MinZ >= box.Min.Z)
            {
                if (!pointInXY(box.Max.X, box.Max.Y) || !pointInXY(box.Min.X, box.Max.Y) || !pointInXY(box.Min.X, box.Min.Y) || !pointInXY(box.Max.X, box.Min.Y))
                    return ContainmentType.Intersects;

                return ContainmentType.Contains;
            }

            if (!pointInXY(box.Max.X, box.Max.Y) || !pointInXY(box.Min.X, box.Max.Y) || !pointInXY(box.Min.X, box.Min.Y) || !pointInXY(box.Max.X, box.Min.Y))
                return ContainmentType.Disjoint;

            return ContainmentType.Intersects;
        }

        public bool Equals(BoundingCylinderXY other)
        {
            return this.Center == other.Center && this.Radius == other.Radius && this.MinZ == other.MinZ && this.MaxZ == other.MaxZ;
        }

        public override bool Equals(object obj)
        {
            if (obj is BoundingCylinderXY)
                return this.Equals((BoundingCylinderXY)obj);

            return false;
        }

        public override int GetHashCode()
        {
            return this.Center.GetHashCode() + this.Radius.GetHashCode() + this.MaxZ.GetHashCode() + this.MinZ.GetHashCode();
        }

        public static bool operator ==(BoundingCylinderXY a, BoundingCylinderXY b)
        {
            return a.Equals(b);
        }

        public static bool operator !=(BoundingCylinderXY a, BoundingCylinderXY b)
        {
            return !a.Equals(b);
        }

        public override string ToString()
        {
            return string.Format("{{Center:{0} Radius:{1} MinZ:{2} MaxZ:{3}}}", this.Center.ToString(), this.Radius.ToString(), this.MinZ.ToString(), this.MaxZ.ToString());
        }

        bool pointInXY(float X, float Y)
        {
            float distSquare = (X - Center.X) * (X - Center.X) + (Y - Center.Y) * (Y - Center.Y);
            return distSquare <= Radius * Radius;
        }
        #endregion
    }
}